.Dd September 21, 2025
.Dt R_ASM 3
.Os
.Sh NAME
.Nm r_asm
.Nd Assembler and disassembler library for radare2
.Sh SYNOPSIS
.In r_asm.h
.Pp
.Sh DESCRIPTION
The
.Nm r_asm
API exposes radare2's high level assembler and disassembler primitives and the glue between them.
.Pp
.Pp
It is implemented as a frontend for the r_arch api that provides the architecture logic to encode and decode instructions. But offers support for multiline assembler with directive handling and pseudo disassembling and parsing plugins.
Routines operate on the
.Vt RAsm
context which holds architecture configuration, current program counter and parser state. Results for multi-instruction operations are returned in
.Vt RAsmCode
objects which contain raw bytes, the disassembly text and per-assembly metadata.
.Sh INITIALIZATION
Before assembling or disassembling you must create and configure an
.Vt RAsm
.instance. Typical setup includes selecting the architecture, the bit width and the program counter. When used from a higher-level component (for example from
.Nm r2
.core code), the
.Vt RAsm
.context can store a user pointer (via
.Fn r_asm_set_user_ptr ()
.) pointing to a
.Vt RCore
.so some helpers (like address-size prediction) work correctly.
.Pp
.Bd -literal -offset indent
/* Initialization API (prototypes) */
RParse *r_parse_new (void);
void r_parse_free (RParse *p);

RAsm *r_asm_new (void);
void r_asm_free (RAsm *a);
void r_asm_set_user_ptr (RAsm *a, void *user);
bool r_asm_use (RAsm *a, const char *name);
int r_asm_set_bits (RAsm *a, int bits);
int r_asm_set_pc (RAsm *a, ut64 pc);
.Ed
Example initialization and cleanup:
.Bd -literal -offset indent
RAsm *a = r_asm_new();
/* choose architecture and word size */
r_asm_use (a, "x86");
r_asm_set_bits (a, 64);
/* set current location for relative operands and disassembly helpers */
r_asm_set_pc (a, 0x1000);
/* when embedding in r2: r_asm_set_user_ptr (a, core); */

r_asm_free (a);
.Ed
.Sh ASSEMBLY
The assembler API provides two levels of convenience. Use
.Fn r_asm_assemble ()
when you need multi-line assembly, directive handling or want a
.Vt RAsmCode
result with both bytes and the produced assembly text. For single-line or binding-specific assembly callbacks use
the lower-level encode callbacks that plugins expose.
If you only need a raw buffer of bytes from a textual instruction, the utility
.Fn r_asm_from_string ()
.returns a malloc'ed byte buffer and its length.
.Pp
.Bd -literal -offset indent
/* Assembly API (prototypes) */
RAsmCode* r_asm_assemble (RAsm *a, const char *buf);
ut8 *r_asm_from_string (RAsm *a, ut64 addr, const char *b, int *l);
void r_asm_code_free (RAsm *acode);
.Ed
The assembler honors directives embedded in the input (such as
.Em .bits ,
.Em .arch , or
.Em .endian ) and uses the configured parser plugin to support pseudo-instructions.
.Bd -literal -offset indent
/* assemble several instructions and inspect bytes */
RAsmCode *code = r_asm_assemble (a, "mov rax, 42\nnop");
if (code) {
    for (int i = 0; i < code->len; i++) {
        printf ("%02x ", code->bytes[i]);
    }
    printf ("%s\n", code->assembly);
    r_asm_code_free (code);
}

/* get a plain buffer (useful for embedding into other APIs) */
int len;
ut8 *buf = r_asm_from_string (a, 0x1000, "add eax, 1", &len);
if (buf) { free (buf); }
.Ed
.Sh DISASSEMBLY
There are two complementary disassembly APIs. The low-level
.Fn r_asm_disassemble ()
.decodes a single instruction into a
.Vt RAnalOp
.structure (size, mnemonic, operands and auxiliary analysis data) and is the preferred API when you need per-instruction fields or to feed the result to the analysis engine. The convenience API
.Fn r_asm_mdisassemble ()
.walks a buffer producing a
.Vt RAsmCode
.where the assembly for each decoded instruction is appended into a single string; it is useful for quick dumps or tools that only need textual output.
.Pp
.Bd -literal -offset indent
/* Disassembly API (prototypes) */
int r_asm_disassemble (RAsm *a, RAnalOp *op, const ut8 *buf, int len);
RAsmCode* r_asm_mdisassemble (RAsm *a, const ut8 *buf, int len);
char *r_asm_tostring (RAsm *a, ut64 addr, const ut8 *b, int l);
RAsmCode* r_asm_mdisassemble_hexstr (RAsm *a, RParse *p, const char *hexstr);
void r_asm_op_init (RAnalOp *op);
void r_asm_op_fini (RAnalOp *op);
.Ed
The typical decoding loop used in
.Nm rasm2
and other tools calls
.Fn r_asm_disassemble ()
repeatedly, updates the PC via
.Fn r_asm_set_pc (),
and finalizes each
.Vt RAnalOp
with
.Fn r_asm_op_fini ().
.Bd -literal -offset indent
/* decode a buffer instruction-by-instruction */
RAnalOp op;
int off = 0;
while (off < buflen) {
    r_asm_op_init (&op);
    r_asm_set_pc (a, base_addr + off);
    int sz = r_asm_disassemble (a, &op, buf + off, buflen - off);
    if (sz <= 0) { break; }
    printf ("%s\n", op.mnemonic);
    off += op.size;
    r_asm_op_fini (&op);
}
.Ed

For quick textual conversion of a byte buffer use
.Fn r_asm_tostring ()
or
.Fn r_asm_mdisassemble ()
; to parse a hex string and optionally run the pseudo-assembly parser pass use
.Fn r_asm_mdisassemble_hexstr ().
.Sh PARSING
The assembler includes a lightweight parse/filter layer used to transform or annotate the produced assembly. The
.Vt RParse
.structure controls filters such as pseudo-assembly, immediate trimming and variable substitution. Parser plugins are architecture-specific and can be selected with
.Fn r_asm_use_parser ().
.Pp
.Bd -literal -offset indent
/* Parsing API (prototypes) */
RParse *r_parse_new (void);
void r_parse_free (RParse *p);
bool r_asm_use_parser (RAsm *a, const char *name);
char *r_asm_parse_pseudo (RAsm *a, const char *data);
.Ed
Common usage patterns are: run
.Fn r_asm_mdisassemble_hexstr ()
with an
.Vt RParse
instance to post-process a hex string, or call
.Fn r_asm_parse_pseudo ()
on a previously decoded mnemonic to get a human-friendly representation (for example replacing memory operands with symbolic names). Example:
.Bd -literal -offset indent
RParse *p = r_parse_new();
p->pseudo = true; /* enable pseudo transformations */
RAsmCode *c = r_asm_mdisassemble_hexstr (a, p, "4868 2a000000");
if (c) { printf ("%s\n", c->assembly); r_asm_code_free (c); }
r_parse_free (p);
.Ed
.Sh EXAMPLES
Below are short examples that mirror patterns used across the codebase (see
.Pq libr/main/rasm2.c
and
.Pq libr/core/cmd_print.inc.c
for complete usages).
.Pp
Assemble multiple lines and print the encoded bytes:
.Bd -literal -offset indent
RAsmCode *ac = r_asm_assemble (a, ".bits 64\nmov rax, 42\nnop");
if (ac) {
    for (int i = 0; i < ac->len; i++) printf ("%02x", ac->bytes[i]);
    r_asm_code_free (ac);
}
.Ed
.Pp
Assemble and analyze instructions producing ESIL (pattern used by the
.Nm r2
commands that print analysis):
.Bd -literal -offset indent
RAsmCode *acode = r_asm_assemble (a, "mov rax, 42\nadd rax, 1");
if (acode) {
    RAnalOp aop = {0};
    int printed = 0;
    while (printed < acode->len) {
        aop.size = 0;
        if (r_anal_op (anal, &aop, base_addr, acode->bytes + printed, acode->len - printed,
                       R_ARCH_OP_MASK_ESIL) > 0) {
            printf ("%s\n", R_STRBUF_SAFEGET (&aop.esil));
        }
        printed += aop.size;
        r_anal_op_fini (&aop);
    }
    r_asm_code_free (acode);
}
.Ed
.Pp
Disassemble a hex string and run the pseudo-parser (as used by the print command):
.Bd -literal -offset indent
RParse *p = r_parse_new();
p->pseudo = true;
RAsmCode *c = r_asm_mdisassemble_hexstr (a, p, "4868 2a000000");
if (c) { puts (c->assembly); r_asm_code_free (c); }
r_parse_free (p);
.Ed
.Sh SEE ALSO
.Xr r_arch 3 ,
.Xr r_anal 3 ,
.Xr r_core 3
